package com.yearno.common.utils

import android.util.Base64
import android.util.Log
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

const val ALGORITHM = "DES"

/**
 * DES加密算法
 * 这个加密算法是对称的加密算法
 * 这个加密算法，在本系统中的应用，主要是因为该加密算法加密后
 * 密文都是字符串和数字的，没有其他字符。这样的密文可以应用在url地址上，
 * 不用担心被URL 地址上传递的数字被转义
 * @author Administrator
 */
enum class DecryptUtil {
    INSTANCE;

    /**
     * 解密：对加密后的十六进制字符串(hex)进行解密，并返回字符串
     *
     * @param encryptedStr 需要解密的，加密后的十六进制字符串
     * @return 解密后的字符串
     */
    fun decrypt(encryptedStr: String, key: String, iv: String): String? {
        try {
            val ivParameterSpec = IvParameterSpec(iv.toByteArray(charset("UTF-8")))
            val skeySpec = SecretKeySpec(key.toByteArray(charset("UTF-8")), "AES")
            val cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING")
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec)
            val decode = Base64.decode(encryptedStr, Base64.DEFAULT)
            val original = cipher.doFinal(decode)
            val decrypt = String(original, charset("UTF-8"))
            Log.d("aes", "encryptedStr: $encryptedStr decrypt: $decrypt")
            return decrypt
        } catch (ex: Exception) {
            ex.printStackTrace()
        }
        return null
    }

    /** 加密算法,可用 DES,DESede,Blowfish.  */

    /**
     * DES解密算法
     * @param data
     * @param cryptKey 密钥 要是偶数
     * @return
     * @throws Exception
     */
    @Throws(java.lang.Exception::class)
    fun decrypt(data: String, cryptKey: String): String {
        return String(
            decrypt(
                hex2byte(data.toByteArray()),
                cryptKey.toByteArray()
            )
        )
    }

    @Throws(java.lang.Exception::class)
    fun decryptBase64(data: String, cryptKey: String): String {
        return String(
            decrypt(
                Base64.decode(data.toByteArray(), Base64.DEFAULT),
                cryptKey.toByteArray()
            )
        )
    }

    /**
     * DES加密算法
     * @param data
     * @param cryptKey
     * @return
     * @throws Exception
     */
    @Throws(java.lang.Exception::class)
    fun encrypt(data: String, cryptKey: String): String {
        return byte2hex(encrypt(data.toByteArray(), cryptKey.toByteArray()))
    }

    @Throws(java.lang.Exception::class)
    fun encryptBase64(data: String, cryptKey: String): String {
        return Base64.encodeToString(
            encrypt(data.toByteArray(), cryptKey.toByteArray()),
            Base64.NO_WRAP
        )
    }

    @Throws(java.lang.Exception::class)
    private fun encrypt(data: ByteArray, key: ByteArray): ByteArray {
        // DES算法要求有一个可信任的随机数源
        val sr = SecureRandom()
        // 从原始密匙数据创建DESKeySpec对象
        val dks = DESKeySpec(key)
        // 创建一个密匙工厂，然后用它把DESKeySpec转换成
        // 一个SecretKey对象
        val keyFactory = SecretKeyFactory.getInstance(ALGORITHM)
        val securekey = keyFactory.generateSecret(dks)
        // Cipher对象实际完成加密操作
        val cipher = Cipher.getInstance(ALGORITHM)
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.ENCRYPT_MODE, securekey, sr)
        // 现在，获取数据并加密
        // 正式执行加密操作
        return cipher.doFinal(data)
    }

    @Throws(java.lang.Exception::class)
    private fun decrypt(data: ByteArray, key: ByteArray): ByteArray {
        // DES算法要求有一个可信任的随机数源
        val sr = SecureRandom()
        // 从原始密匙数据创建一个DESKeySpec对象
        val dks = DESKeySpec(key)
        // 创建一个密匙工厂，然后用它把DESKeySpec对象转换成
        // 一个SecretKey对象
        val keyFactory = SecretKeyFactory.getInstance(ALGORITHM)
        val securekey = keyFactory.generateSecret(dks)
        // Cipher对象实际完成解密操作
        val cipher = Cipher.getInstance(ALGORITHM)
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, sr)
        // 现在，获取数据并解密
        // 正式执行解密操作
        return cipher.doFinal(data)
    }

    private fun hex2byte(b: ByteArray): ByteArray {
        require(b.size % 2 == 0) { "长度不是偶数" }
        val b2 = ByteArray(b.size / 2)
        var n = 0
        while (n < b.size) {
            val item = String(b, n, 2)
            b2[n / 2] = item.toInt(16).toByte()
            n += 2
        }
        return b2
    }

    private fun byte2hex(b: ByteArray): String {
        var hs = ""
        var stmp = ""
        for (n in b.indices) {
            val v = b[n].toInt() and 0xFF
            stmp = Integer.toHexString(v)
            hs = if (stmp.length == 1) hs + "0" + stmp else hs + stmp
        }
        return hs.toUpperCase()
    }
}